"""
认证数据验证模式
使用marshmallow定义数据验证规则
"""
from marshmallow import Schema, fields, validate, validates, ValidationError
from app.auth.utils import validate_password_strength
from app.utils.validators import validate_email, validate_username

class LoginSchema(Schema):
    """登录数据验证模式"""
    
    username = fields.Str(
        required=True,
        validate=validate.Length(min=3, max=50),
        error_messages={'required': '用户名不能为空'}
    )
    password = fields.Str(
        required=True,
        validate=validate.Length(min=1),
        error_messages={'required': '密码不能为空'}
    )
    remember_me = fields.Bool(missing=False)
    
    @validates('username')
    def validate_username_format(self, value):
        """验证用户名格式"""
        if not validate_username(value):
            raise ValidationError('用户名格式不正确')

class RegisterSchema(Schema):
    """注册数据验证模式"""
    
    username = fields.Str(
        required=True,
        validate=validate.Length(min=3, max=50),
        error_messages={'required': '用户名不能为空'}
    )
    email = fields.Email(
        required=True,
        error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式不正确'}
    )
    password = fields.Str(
        required=True,
        validate=validate.Length(min=8, max=128),
        error_messages={'required': '密码不能为空'}
    )
    confirm_password = fields.Str(required=True)
    agree_terms = fields.Bool(required=True)
    
    @validates('username')
    def validate_username_format(self, value):
        """验证用户名格式"""
        if not validate_username(value):
            raise ValidationError('用户名只能包含字母、数字、下划线和连字符')
        
        # 检查保留用户名
        reserved_names = ['admin', 'administrator', 'root', 'system', 'test']
        if value.lower() in reserved_names:
            raise ValidationError('该用户名不可用')
    
    @validates('password')
    def validate_password_strength(self, value):
        """验证密码强度"""
        is_valid, message = validate_password_strength(value)
        if not is_valid:
            raise ValidationError(message)
    
    @validates('confirm_password')
    def validate_password_match(self, value):
        """验证密码确认"""
        if 'password' in self.context and value != self.context['password']:
            raise ValidationError('两次输入的密码不一致')

class ChangePasswordSchema(Schema):
    """修改密码数据验证模式"""
    
    current_password = fields.Str(required=True)
    new_password = fields.Str(
        required=True,
        validate=validate.Length(min=8, max=128)
    )
    confirm_password = fields.Str(required=True)
    
    @validates('new_password')
    def validate_password_strength(self, value):
        """验证新密码强度"""
        is_valid, message = validate_password_strength(value)
        if not is_valid:
            raise ValidationError(message)
    
    @validates('confirm_password')
    def validate_password_match(self, value):
        """验证密码确认"""
        if 'new_password' in self.context and value != self.context['new_password']:
            raise ValidationError('两次输入的密码不一致')

class ResetPasswordRequestSchema(Schema):
    """重置密码请求数据验证模式"""
    
    email = fields.Email(
        required=True,
        error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式不正确'}
    )

class ResetPasswordSchema(Schema):
    """重置密码数据验证模式"""
    
    token = fields.Str(required=True)
    new_password = fields.Str(
        required=True,
        validate=validate.Length(min=8, max=128)
    )
    confirm_password = fields.Str(required=True)
    
    @validates('new_password')
    def validate_password_strength(self, value):
        """验证新密码强度"""
        is_valid, message = validate_password_strength(value)
        if not is_valid:
            raise ValidationError(message)
    
    @validates('confirm_password')
    def validate_password_match(self, value):
        """验证密码确认"""
        if 'new_password' in self.context and value != self.context['new_password']:
            raise ValidationError('两次输入的密码不一致')

class UpdateProfileSchema(Schema):
    """更新个人资料数据验证模式"""
    
    username = fields.Str(
        validate=validate.Length(min=3, max=50),
        allow_none=True
    )
    email = fields.Email(
        allow_none=True,
        error_messages={'invalid': '邮箱格式不正确'}
    )
    bio = fields.Str(
        validate=validate.Length(max=500),
        allow_none=True
    )
    avatar_url = fields.Url(allow_none=True)
    
    @validates('username')
    def validate_username_format(self, value):
        """验证用户名格式"""
        if value and not validate_username(value):
            raise ValidationError('用户名只能包含字母、数字、下划线和连字符')

class VerificationSchema(Schema):
    """验证码验证模式"""
    
    code = fields.Str(
        required=True,
        validate=validate.Length(min=6, max=6),
        error_messages={'required': '验证码不能为空'}
    )

class TwoFactorSchema(Schema):
    """双因素认证验证模式"""
    
    code = fields.Str(
        required=True,
        validate=validate.Length(min=6, max=6),
        error_messages={'required': '验证码不能为空'}
    )
    method = fields.Str(
        validate=validate.OneOf(['totp', 'sms', 'email']),
        missing='totp'
    )

class APIKeySchema(Schema):
    """API密钥生成模式"""
    
    name = fields.Str(
        required=True,
        validate=validate.Length(min=1, max=100),
        error_messages={'required': '密钥名称不能为空'}
    )
    permissions = fields.List(
        fields.Str(validate=validate.OneOf(['read', 'write', 'admin'])),
        missing=['read']
    )
    expires_in = fields.Int(
        validate=validate.Range(min=1, max=365*5),  # 最多5年
        missing=365  # 默认1年
    )